// @Author EthanScriptOn
// @Desc
package mysql_define

import (
	"fmt"
	"gitee.com/fatzeng/srf_switch_basic_components/common/identity"
	"gitee.com/fatzeng/srf_switch_basic_components/switch_log"
	"gitee.com/fatzeng/srf_switch_basic_components/util"
	"gitee.com/fatzeng/srf_switch_expansion_package/extend_config"
	"gitee.com/fatzeng/srf_switch_expansion_package/extend_param_builder"
	"gitee.com/fatzeng/srf_switch_expansion_package/extend_param_collector"
	"gitee.com/fatzeng/srf_switch_expansion_package/extend_parser"
	"gitee.com/fatzeng/srf_switch_stream_bridge/bridge"
	"gitee.com/fatzeng/srf_switch_stream_bridge/framework/operator"
	"gitee.com/fatzeng/srf_switch_stream_bridge/framework/operator/op_example"
	"gitee.com/fatzeng/srf_switch_stream_bridge/param_collector"
	"gitee.com/fatzeng/srf_switch_stream_bridge/result_collector"
	"reflect"
	"time"
)

const MYSQL_FOREGROUND_TIME_OUT = "MYSQL_FOREGROUND_TIME_OUT"
const MYSQL_FOREGROUND_EXEC = "MYSQL_FOREGROUND_EXEC"
const MYSQL_FOREGROUND_BRIDGE_CONFIG = "MYSQL_FOREGROUND_BRIDGE_CONFIG"

var mysqlForegroundTimeOutOnceInitializer = util.GenerateOnceInitializer(func() (result interface{}, err error) {
	mysqlTimeOutOperator := op_example.TimeoutDetectionMultiChannelDataOperator{
		IdentityInformationCarrier: identity.GenerateIdentityInformationCarrierWithIdentity(MYSQL_FOREGROUND_TIME_OUT),
	}
	err = operator.AddOperator(&mysqlTimeOutOperator)
	if err != nil {
		return nil, err
	}
	return &mysqlTimeOutOperator, nil
})

func getMysqlForegroundTimeoutOperator() operator.MultiChannelDataOperator {
	get, err := mysqlForegroundTimeOutOnceInitializer.Get()
	if err != nil {
		switch_log.Logger().Error("get mysql timeout operator error: ", err)
		panic(err)
	}
	return get.(operator.MultiChannelDataOperator)
}

var mysqlExecOnceInitializer = util.GenerateOnceInitializer(func() (result interface{}, err error) {
	mysqlTimeOutOperator := op_example.TimeoutDetectionMultiChannelDataOperator{
		IdentityInformationCarrier: identity.GenerateIdentityInformationCarrierWithIdentity(MYSQL_FOREGROUND_EXEC),
	}
	err = operator.AddOperator(&mysqlTimeOutOperator)
	if err != nil {
		return nil, err
	}
	return &mysqlTimeOutOperator, nil
})

func getMysqlExecOperator() operator.MultiChannelDataOperator {
	get, err := mysqlExecOnceInitializer.Get()
	if err != nil {
		switch_log.Logger().Error("get mysql exec operator error: ", err)
		panic(err)
	}
	return get.(operator.MultiChannelDataOperator)
}

func getForegroundOperatorConfigIdentifier() (identifier interface{}, err error) {
	execOperator := getMysqlExecOperator()
	identifier, err = execOperator.GenerateUniqueIdentifier()
	if err != nil {
		switch_log.Logger().Error("get mysql exec operator identifier error: ", err)
		return nil, err
	}
	execConfig := operator.LoopMultiChannelDataOperatorConfig{
		BasicMultiChannelDataOperatorConfig: operator.GenerateBasicMultiChannelDataOperatorConfig(MYSQL_FOREGROUND_EXEC, identifier, nil),
	}
	err = operator.AddOperatorConfig(execConfig)
	if err != nil {
		switch_log.Logger().Error("add mysql exec operator config error: ", err)
		return nil, err
	}

	timeoutInstance := getMysqlForegroundTimeoutOperator()
	timeoutIdentifier, err := timeoutInstance.GenerateUniqueIdentifier()
	if err != nil {
		switch_log.Logger().Error("get mysql timeout operator identifier error: ", err)
		return nil, err
	}
	timeoutConfig := operator.TimeOutMultiChannelDataOperatorConfig{
		BasicMultiChannelDataOperatorConfig: operator.GenerateBasicMultiChannelDataOperatorConfig(MYSQL_FOREGROUND_TIME_OUT, timeoutIdentifier, execConfig),
		TimeOut:                             5 * time.Second,
	}
	err = operator.AddOperatorConfig(timeoutConfig)
	if err != nil {
		switch_log.Logger().Error("add mysql timeout operator config error: ", err)
		return nil, err
	}

	return MYSQL_FOREGROUND_TIME_OUT, nil
}

type SqlForegroundParamsCollector struct {
}

func (s *SqlForegroundParamsCollector) Collect(emptyParam interface{}) error {
	params, ok := emptyParam.(*extend_param_collector.SqlParams)
	if !ok {
		return fmt.Errorf("param type error")
	}
	params.Command.WriteString("insert into table values(${value1},${value2})")
	params.CommandArgs["value1"] = "1"
	params.CommandArgs["value2"] = "2"
	return nil
}

func (s *SqlForegroundParamsCollector) ShouldExecute() bool {
	return true
}

func mysqlForegroundBridgeConfigParamCollector() []param_collector.BridgeParamCollector {
	return []param_collector.BridgeParamCollector{&SqlForegroundParamsCollector{}}
}

func MysqlForegroundBridgeConfig() *bridge.BridgeConfig {
	timeoutOperator := getMysqlForegroundTimeoutOperator()
	identifier, err := timeoutOperator.GenerateUniqueIdentifier()
	if err != nil {
		switch_log.Logger().Error("get mysql timeout operator identifier error: ", err)
		return nil
	}
	configIdentifier, err := getForegroundOperatorConfigIdentifier()
	if err != nil {
		switch_log.Logger().Error("get mysql operator config identifier error: ", err)
		return nil
	}
	return &bridge.BridgeConfig{
		BridgeIdentifier:                   MYSQL_FOREGROUND_BRIDGE_CONFIG,
		DataSource:                         extend_config.MYSQL,
		OperatorConfigIdentifier:           configIdentifier,
		MultiChannelDataOperatorIdentifier: identifier,
		ParamsCollectors:                   mysqlForegroundBridgeConfigParamCollector,
		ParamType:                          reflect.TypeOf(new(extend_param_collector.SqlParams)),
		ParamsBuilder:                      &extend_param_builder.SqlParamsBuilder{},
		ResultType:                         reflect.TypeOf(extend_config.MysqlExecResponse{}),
		ResultParser:                       &extend_parser.MysqlExecResponseParser{},
		ResultCollector:                    &result_collector.DefaultBridgeResultCollector{},
	}
}
